package main

import (
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"stick/protocol"
)

type ServerConn struct {
	Conn net.Conn
	Dch  chan struct{}
	File *os.File
}

func newServerConn(conn net.Conn) *ServerConn {
	return &ServerConn{
		Conn: conn,
		Dch:  make(chan struct{}),
	}
}

func main() {
	listen, err := net.Listen("tcp", "127.0.0.1:9090")
	if err != nil {
		log.Fatalf("failed tcp, err=%v", err)
	}
	fmt.Println("已初始化连接，等待客户端连接...")
	defer listen.Close()
	for {
		conn, err := listen.Accept()
		if err != nil {
			fmt.Println("Failed accept, err = ", err)
			continue
		}
		serverConn := newServerConn(conn)
		go serverConn.Handler()
		go serverConn.CloseConn()
	}
}

func (server *ServerConn) Handler() {
	fmt.Println("来自客服端 ", server.Conn.RemoteAddr().String())
	defer server.Conn.Close()
	reader := io.Reader(server.Conn)

	for {

		data, err := protocol.FileHeaderDecode(reader)
		if err != nil {
			fmt.Println("没有收到来自" + server.Conn.RemoteAddr().String() + "消息。。。。")
			continue
		}

		// 1. 心跳响应
		if data.Heartbeat == protocol.Heartbeat {
			fmt.Println("心跳响应......")
			go server.HandlerHeartbeat()
			continue
		}

		// 2. 处理文件
		switch data.FileType {
		case protocol.FileTypeName:
			// 1. 获取文件名称
			fileName := *data.Content

			// 1.2 回应客户端收到
			if *data.Content == "" {
				continue
			}

			file, err := os.Create(fileName)
			if err != nil {
				fmt.Println("创建文件失败")
				panic(fmt.Errorf("创建文件失败err=%v", err))
			}
			server.File = file

			// 2. 处理应答
			if data.MessageType == protocol.RequestMessage || data.MessageType == protocol.ResponseMessage {
				go server.ResponseMessage(
					protocol.NoHeartbeat,
					protocol.ResponseMessage,
					protocol.FileTypeFile,
					protocol.AcceptSuccess)
				continue
			}
		case protocol.FileTypeFile:

			// 2. 文件读完的
			if *data.Content == protocol.ReadFinish {
				fmt.Println("已经读完了")
				server.Dch <- struct{}{}
				return
			}

			if err != nil {
				fmt.Println("解析失败 err=", err)
				return
			}

			_, err := server.File.Write([]byte(*data.Content))
			if err != nil {
				fmt.Println("未创建文件流 err=", err)
				return
			}
			server.File.Write([]byte("\n"))

		case protocol.FileTypeJson:
			fmt.Println(*data.Content)
			server.Dch <- struct{}{}
			return
		default:

		}

	}
}

// CloseConn 关闭连接
func (server *ServerConn) CloseConn() {
	select {
	case <-server.Dch:
		fmt.Println("关闭来自 " + server.Conn.RemoteAddr().String() + " 连接。。。")
		server.Conn.Close()
		server.File.Close()
		close(server.Dch)
	}
}

// HandlerHeartbeat 处理心跳
func (server *ServerConn) HandlerHeartbeat() {
	server.ResponseMessage(
		protocol.Heartbeat,
		protocol.NormalMessage,
		protocol.FileTypeText,
		protocol.HeartbeatContext)
}

// ResponseMessage 需要响应消息
func (server *ServerConn) ResponseMessage(heartbeat, messageType, fileType byte, message string) {
	acceptBuf, err := protocol.FileHeaderEncode(
		heartbeat,
		messageType,
		fileType,
		message)

	if err != nil {
		fmt.Println("回应收到文件名称失败。。。。")
		return
	}
	_, err = server.Conn.Write(acceptBuf)
	if err != nil {
		fmt.Printf("写入失败 message=%s\n", message)
		return
	}
}
